using System;
using System.IO;
using System.Text;
using BSDS.Core.Data.Local.Csv.Parsing;
using BSDS.Core.Model;
using BSDS.Core.Model.Data;
using System.Collections.Generic;

namespace BSDS.Core.Data.Local.Csv.Serialization
{
    public class CsvFormatSerializer : ISerializer
    {
        private readonly CsvSeparator separator;

        public CsvFormatSerializer(DataFormat format)
        {
            separator = CsvType.Parse(format.Value).Separator;
        }

        public void Serialize(EntityValue[] entities, string entityTypeName, string filename)
        {
            Serialize(entities, entityTypeName, filename, SerializationOptions.None);
        }

        public void Serialize(EntityValue[] entities, string entityTypeName, string filename, SerializationOptions options)
        {
            using (var writer = new StreamWriter(new FileStream(filename, FileMode.Create)))
            {
                if (options == SerializationOptions.SerializeToPortal)
                {
                    const string portalLineTemplate = "Bing Spatial Data Services,1.0,{0}";

                    writer.WriteLine(string.Format(portalLineTemplate, entityTypeName));
                }

                writer.WriteLine(CreateSchemaDeclaration(entities[0].AttributeInfos, options));

                foreach (var entity in entities)
                {
                    writer.WriteLine(SerializeEntity(entity, options));
                }
            }
        }

        private string SerializeEntity(EntityValue entity, SerializationOptions options)
        {
            var utils = new SerializationUtils();
            var entityBuilder = new StringBuilder();

            for(int i=0; i<entity.AttributeValues.Count; i++)
            {
                var value = utils.GetValue(entity.AttributeValues[i], options);

                if(separator == CsvSeparator.Comma && value.Contains(","))
                {
                    value = "\"" + value + "\"";
                }

                entityBuilder.Append(value);

                if (i < entity.AttributeValues.Count - 1)
                {
                    entityBuilder.Append(separator.Value);
                }
            }

            return entityBuilder.ToString();
        }

        private string CreateSchemaDeclaration(List<AttributeInfo> attributeInfos, SerializationOptions options)
        {
            var headerBuilder = new StringBuilder();

            for (int i = 0; i < attributeInfos.Count; i++)
            {
                headerBuilder.Append(CreateHeaderElement(attributeInfos[i], options));

                if (i < attributeInfos.Count - 1)
                {
                    headerBuilder.Append(separator.Value);
                }
            }

            return headerBuilder.ToString();
        }

        private static string CreateHeaderElement(AttributeInfo attributeInfo, SerializationOptions option)
        {
            var primaryKeySuffix = "@primaryKey";

            if (option == SerializationOptions.SerializeToPortal)
            {
                primaryKeySuffix = ",primaryKey";
            }
            return String.Format("{0}(Edm.{1})", attributeInfo.Name, 
                ConvertDataType(attributeInfo.Datatype) + (attributeInfo.IsPrimaryKey ? primaryKeySuffix : string.Empty));
        }

        private static string ConvertDataType(string datatype)
        {
            if(datatype == "long")
            {
                return "Int64";
            }
            if(datatype.ToLower() == "datetime")
            {
                return "DateTime";
            }
            
            return datatype.Substring(0, 1).ToUpper() + datatype.Substring(1, datatype.Length - 1);
        }
    }
}